#include <boost/foreach.hpp>

#include "suffix_array.h"

sastring::sastring(const std::string& s) 
  : std::string(s), T(NULL), SA(NULL), result(0) 
{ 
  build_sa(); 
}

sastring::sastring(const sastring& s) 
  : std::string(s), T(NULL), SA(NULL), result(0) 
{ 
  copy_pointer(s);
}
sastring::sastring() 
  : std::string(), T(NULL), SA(NULL), result(0) 
{
}
  
sastring& sastring::operator=(const std::string& s) 
{
  this->std::string::operator=(s);
  build_sa();
  return *this;
}

sastring& sastring::operator=(const sastring& s) 
{
  this->std::string::operator=(s);
  copy_pointer(s);
  return *this;
}

sastring::~sastring() 
{
  if (T) delete T;
  if (SA) delete SA;
}

void sastring::sasearch(const std::string& p, int& left, int& size) const 
{
  if (p.empty()) {
    left = 0;
    size = this->length();
    return;
  }
  sauchar_t *P = NULL;
  str2sachar(p, &P);
  size = sa_search(T, this->length(), P, p.length(), SA, this->length(), &left);
  delete P;
}

void sastring::build_sa() 
{
  if (T) delete T;
  if (SA) delete SA;
  T = NULL;
  SA = NULL;
  if (this->empty()) return;
      
  int n = this->length();
  str2sachar(*this, &T);
  SA = new saidx_t[n];
  result = divsufsort(T, SA, n);
  //MSG("DONE 2");
}

void sastring::str2sachar(const std::string& s, sauchar_t** T) 
{
  int n = s.length();
  *T = new sauchar_t[n];
  for (int i = 0; i < n; i++) (*T)[i] = s[i];
  //MSG("DONE 1");
}
		
void sastring::copy_pointer(const sastring& s)
{
  int n = s.length();
  T = new sauchar_t[n];
  SA = new saidx_t[n];
  for (int i = 0; i < n; i++) {
    T[i] = s.T[i];
    SA[i] = s.SA[i];				
  }
  result = s.result;
}

int sastring::pattern_count(const std::vector<sastring>& SAVEC, const std::string& p, 
			    int periodic, uint frame)
{
  int count = 0;
  BOOST_FOREACH(const sastring& s, SAVEC) {
    int left, size, right;
    s.sasearch(p, left, size);
    right = left+size;
    for (int i = left; i < right; i++)
      if (s.SA[i]+p.length() % periodic == frame) count++; 
  }
  return count;
}

std::vector<int> sastring::pattern_count(const std::vector<sastring>& SAVEC, const std::string& p, int periodic)
{
  std::vector<int> count(periodic, 0);
  BOOST_FOREACH(const sastring& s, SAVEC) {
    int left, size, right, frame;
    s.sasearch(p, left, size);
    right = left+size;
    for (int i = left; i < right; i++) {
      frame = s.SA[i]+p.length() % periodic;
      count[frame]++;
    } 
  }
  return count;
}
